# -*- coding: utf-8 -*-
"""
weather_react_agent.py
ReAct 版本的“天气 + 穿衣建议”Agent：
- 使用 LangGraph 的 create_react_agent 实现 Reason↔Act 循环
- 工具1：get_weather(city)  -> 返回模拟天气
- 工具2：dress_advice(weather) -> 给穿衣建议
- 支持流式打印 ReAct 每一步（Thought / Tool Call / Observation / Final）
"""

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

# ========== 初始化 LLM ==========
llm = ChatOpenAI(
    api_key="sk-b03b3b81b83a4fe6bb79f68eba4da332",  # ⚠️ 替换为你的 Key；生产建议用环境变量
    base_url="https://api.deepseek.com",
    model="deepseek-chat",
    temperature=0
)


# ========== 工具1：模拟天气查询 ==========
@tool
def get_weather(city: str) -> str:
    """根据城市名称返回模拟天气情况（若未知城市返回提示）。"""
    dummy_weather = {
        "北京": "晴，28°C",
        "上海": "多云，22°C",
        "广州": "小雨，19°C"
    }
    return dummy_weather.get(city, "未找到天气信息")


# ========== 工具2：穿衣建议 ==========
@tool
def dress_advice(weather: str) -> str:
    """根据天气情况给出穿衣建议"""
    if "雨" in weather:
        return "记得带伞，穿防水外套。"
    if "多云" in weather:
        return "适合春秋装，薄外套即可。"
    if "晴" in weather:
        return "建议穿短袖，注意防晒。"
    return "根据体感增减衣物。"


tools = [get_weather, dress_advice]

# ========== 创建 ReAct Agent ==========
# 说明：create_react_agent 会按照 ReAct 模式自动“思考→选工具→观察→再思考…→最终回答”
agent = create_react_agent(
    model=llm,
    tools=tools,
    # 你也可以自定义 system 提示词，引导先查天气再给建议
    prompt=(
        "你是一个勤于思考且会使用工具的助手。\n"
        "当用户询问与穿衣/天气相关的问题时：\n"
        "1) 若未明确天气，请先调用 get_weather(city) 获取天气；\n"
        "2) 拿到天气后，调用 dress_advice(weather) 给出建议；\n"
        "3) 最终回答时简洁明了，并在一段话里给出城市天气摘要 + 穿衣建议。"
    ),
)


def run_once(query: str):
    """
    单次运行：使用流模式把 ReAct 的每一步都打印出来（Thought/Action/Observation/Final）
    """
    print(f"\n🟢 用户：{query}\n")
    # LangGraph 的输入是一个状态字典，这里只需提供 messages
    config = {"configurable": {"thread_id": "weather-thread"}}

    # stream(..., stream_mode="values") 会在每个图状态变化时返回完整状态
    for step in agent.stream({"messages": [{"role": "user", "content": query}]},
                             config=config, stream_mode="values"):
        msg = step["messages"][-1]
        role = getattr(msg, "type", getattr(msg, "role", ""))
        content = getattr(msg, "content", "")
        print(f"[{role}] {content}")
        # LangChain 的消息对象可能有 pretty_print；没有就 fallback 打印
        try:
            msg.pretty_print()
        except Exception:
            print(f"[{role}] {content}")

    print("\n✅ 完成。\n" + "-" * 60)


def main():
    print("🤖 ReAct 天气助手（输入 exit 退出）")
    print("示例：'我在上海要穿什么？' 或 '北京天气怎样，穿啥？'\n")
    while True:
        user_input = input("你：").strip()
        if user_input.lower() == "exit":
            print("👋 再见！")
            break
        run_once(user_input)


if __name__ == "__main__":
    main()
